apt 中的keyrings(gpg)
·
Table of Contents
apt gpg 作用
在 APT 的工作流程中,GPG 签名验证(signed-by= 指定的公钥)是在 “获取 Release 文件并校验其完整性与真实性” 阶段起作用的,具体发生在 apt update 的早期阶段,早于包列表下载和安装决策。
- 解析 sources.list ,识别源 URL 和组件 ( bookworm , stable)
- 下载 InRelease 或 Release + Release.gpg 文件: → https://download.docker.com/linux/debian/dists/bookworm/InRelease 或 → .../Release + .../Release.gpg 关键阶段
- 用 /etc/apt/keyrings/docker.asc 中的公钥验证 InRelease/Release.gpg 签名 ️ GPG 认证生效点
- 若验证失败 → 立即报错退出 (如 NO_PUBKEY , GPG error , signature invalid )
- 若验证成功 → 解析 Release 文件中的 SHA256 / SHA512 校验和 (哈希校验,非 GPG)
- 下载 Packages.gz 等索引文件,并用 Release 中的哈希值校验完整性
- 建立本地包数据库( /var/lib/apt/lists/... )
- apt install 时仅校验 .deb 包哈希(来自 Packages ), 不再 GPG 验证
# 1. 故意破坏签名验证(删掉 keyring)
sudo rm /etc/apt/keyrings/docker.asc
sudo apt update 2>&1 | grep -A2 -B2 "GPG\|NO_PUBKEY"
# → 报错:The following signatures couldn't be verified...
# 2. 或临时禁用验证(危险!仅测试)
sudo apt -o Acquire::Check-Valid-Until=false \
-o Acquire::AllowInsecureRepositories=true \
-o Acquire::AllowDowngradeToInsecureRepositories=true \
update
# → 仍可能失败,因为 signed-by 指定了强制 key,除非改 sources.list 去掉 signed-by
使用镜像源(mirror)的 APT 服务,还能正常 GPG 认证吗?
- 可以,只要镜像同步了完整的 dists/ 目录(含 InRelease / Release + Release.gpg)——绝大多数合规镜像都做到了。
- APT 的 GPG 校验不依赖源服务器域名/IP,只校验: 文件内容是否被篡改(哈希匹配) Release 文件是否由可信私钥签名(GPG 签名校验)
验证实操(推荐)
# 1. 下载 InRelease(中科大镜像)
wget https://mirrors.ustc.edu.cn/docker-ce/linux/debian/dists/bookworm/InRelease
# 2. 用你本地的 docker.asc 公钥验证
gpg --keyring /etc/apt/keyrings/docker.asc \
--verify InRelease
# 应输出:Good signature from "Docker Release (CE deb) ..."
# 3. 对比原始源(应完全一致)
diff InRelease \
<(curl -s https://download.docker.com/linux/debian/dists/bookworm/InRelease)
# → 无输出(完全相同)
报错排查
gpg: [don't know]: invalid packet (ctb=2d)
gpg: keydb_search failed: 无效的数据包
gpg: 无法检查签名:缺少公钥
- 诊断依据 你从 https://download.docker.com/linux/debian/gpg 下载的 gpg 文件(3.7KB)是 ASCII-armored 公钥
- 但 --keyring /path/to/file 默认期望的是 二进制格式的 keyring(或 GnuPG native keybox)
- 当你直接把 ASCII-armored .asc 传给 --keyring,GPG 会把它当二进制解析 → 遇到 -----BEGIN 这种文本头 → 解析为“无效数据包”(ctb=2d 是 0x2d = '-' 字符)→ 失败 ❌
先 dearmor 成二进制,再验证(推荐)
# 1. 确保 docker.asc 是 ASCII-armored(检查开头)
head -n2 /etc/apt/keyrings/docker.asc
# 应输出:-----BEGIN PGP PUBLIC KEY BLOCK-----
# 2. 转成二进制格式(例如 docker.gpg)
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg /etc/apt/keyrings/docker.asc
# 3. 用 .gpg(二进制)验证
gpg --keyring /etc/apt/keyrings/docker.gpg \
--verify ./InRelease
# ✅ 此时应显示:Good signature from "Docker Release (CE deb)..."
不指定 --keyring,而是先导入公钥到临时 keyring
# 创建临时 home
mkdir -p /tmp/gpghome && chmod 700 /tmp/gpghome
# 导入公钥(自动 dearmor)
gpg --homedir /tmp/gpghome --import /etc/apt/keyrings/docker.asc
# 用临时 keyring 验证
gpg --homedir /tmp/gpghome --verify ./InRelease
# 清理
rm -rf /tmp/gpghome
为什么 apt 本身能工作?
因为 APT 内部 自动处理 dearmor! 当你在 sources.list 写:
deb [signed-by=/etc/apt/keyrings/docker.asc] ...
APT 会: 检测 .asc 后缀或文件内容含 -----BEGIN → 自动 dearmor 后加载
不依赖 gpg CLI 行为 → 所以 apt update 正常,但你手动用 gpg --keyring 却失败。
# 查看二进制 keyring 内容
gpg --keyring /etc/apt/keyrings/docker.gpg --list-packets </dev/null
# 应显示 pub, sub 等 key packets,无 "invalid packet"
# 或直接看指纹(对比官网)
gpg --keyring /etc/apt/keyrings/docker.gpg --with-fingerprint --list-keys
# 应含:7EA0 A9C3 F273 FCD8 (即你日志中的 RSA 密钥 ID)
总结:
- .asc 是文本格式,不能直接作 --keyring;必须 --dearmor 转 .gpg 二进制。
- APT 能自动处理,但 gpg CLI 不会 —— 这是常见坑点